//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_comment_api_serv

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/comment_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/requirement_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_comment"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_comment_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectCommentApiImpl) GetUnReadState(ctx context.Context, req *project_comment_api.GetUnReadStateRequest) (*project_comment_api.GetUnReadStateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.GetUnReadStateResponse{
			Code:   project_comment_api.GetUnReadStateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.GetUnReadStateResponse{
			Code:   project_comment_api.GetUnReadStateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.GetUnReadStateResponse{
			Code:   project_comment_api.GetUnReadStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	count, err := comment_dao.UnReadDao.Count(ctx, req.ProjectId, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	return &project_comment_api.GetUnReadStateResponse{
		Code:        project_comment_api.GetUnReadStateResponse_CODE_OK,
		UnReadCount: count,
	}, nil
}

func (apiImpl *ProjectCommentApiImpl) ListUnRead(ctx context.Context, req *project_comment_api.ListUnReadRequest) (*project_comment_api.ListUnReadResponse, error) {
	emptyList := []*project_comment_api.UnReadInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.ListUnReadResponse{
			Code:           project_comment_api.ListUnReadResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			UnReadInfoList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.ListUnReadResponse{
			Code:           project_comment_api.ListUnReadResponse_CODE_NO_PROJECT,
			ErrMsg:         "项目不存在",
			UnReadInfoList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.ListUnReadResponse{
			Code:           project_comment_api.ListUnReadResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			UnReadInfoList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	count, err := comment_dao.UnReadDao.Count(ctx, req.ProjectId, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	unReadItemList, err := comment_dao.UnReadDao.List(ctx, req.ProjectId, sessionItem.UserId, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	titleMap, err := apiImpl.calcTitleMap(ctx, req.ProjectId, unReadItemList)
	if err != nil {
		return nil, err
	}

	//生成结果
	infoList := []*project_comment_api.UnReadInfo{}
	for _, unReadItem := range unReadItemList {
		info := unReadItem.ToUnReadInfo()
		info.Title = titleMap[unReadItem.TargetId]
		infoList = append(infoList, info)
	}

	return &project_comment_api.ListUnReadResponse{
		Code:           project_comment_api.ListUnReadResponse_CODE_OK,
		TotalCount:     count,
		UnReadInfoList: infoList,
	}, nil
}

func (apiImpl *ProjectCommentApiImpl) calcTitleMap(ctx context.Context, projectId string, unReadItemList []*comment_dao.UnReadInfoDbItem) (map[string]string, error) {
	entryIdList := []string{}
	reqIdList := []string{}
	issueIdList := []string{}
	caseIdList := []string{}

	for _, unReadItem := range unReadItemList {
		if unReadItem.TargetType == uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY) {
			entryIdList = append(entryIdList, unReadItem.TargetId)
		}
		if unReadItem.TargetType == uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_REQUIRE_MENT) {
			reqIdList = append(reqIdList, unReadItem.TargetId)
		}
		if unReadItem.TargetType == uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_TASK) {
			issueIdList = append(issueIdList, unReadItem.TargetId)
		}
		if unReadItem.TargetType == uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_BUG) {
			issueIdList = append(issueIdList, unReadItem.TargetId)
		}
		if unReadItem.TargetType == uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_TEST_CASE) {
			caseIdList = append(caseIdList, unReadItem.TargetId)
		}
	}

	retMap := map[string]string{}
	if len(entryIdList) != 0 {
		itemList, err := project_entry_dao.EntryDao.ListById(ctx, entryIdList)
		if err != nil {
			return nil, err
		}
		for _, item := range itemList {
			retMap[item.EntryId] = item.EntryTitle
		}
	}
	if len(reqIdList) != 0 {
		itemList, err := requirement_dao.RequirementInfoDao.ListById(ctx, projectId, reqIdList)
		if err != nil {
			return nil, err
		}
		for _, item := range itemList {
			retMap[item.RequirementId] = item.BaseInfo.Title
		}
	}
	if len(issueIdList) != 0 {
		itemList, err := issue_dao.IssueDao.ListById(ctx, projectId, issueIdList)
		if err != nil {
			return nil, err
		}
		for _, item := range itemList {
			retMap[item.IssueId] = item.BasicInfo.Title
		}
	}
	if len(caseIdList) != 0 {
		itemList, err := testcase_dao.CaseInfoDao.ListById(ctx, projectId, caseIdList)
		if err != nil {
			return nil, err
		}
		for _, item := range itemList {
			retMap[item.CaseId] = item.Title
		}
	}
	return retMap, nil
}

func (apiImpl *ProjectCommentApiImpl) CheckUnRead(ctx context.Context, req *project_comment_api.CheckUnReadRequest) (*project_comment_api.CheckUnReadResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.CheckUnReadResponse{
			Code:   project_comment_api.CheckUnReadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.CheckUnReadResponse{
			Code:   project_comment_api.CheckUnReadResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.CheckUnReadResponse{
			Code:   project_comment_api.CheckUnReadResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := comment_dao.UnReadDao.Exist(ctx, req.ProjectId, sessionItem.UserId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return nil, err
	}
	return &project_comment_api.CheckUnReadResponse{
		Code:      project_comment_api.CheckUnReadResponse_CODE_OK,
		HasUnRead: exist,
	}, nil
}

func (apiImpl *ProjectCommentApiImpl) RemoveUnRead(ctx context.Context, req *project_comment_api.RemoveUnReadRequest) (*project_comment_api.RemoveUnReadResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_comment_api.RemoveUnReadResponse{
			Code:   project_comment_api.RemoveUnReadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_comment_api.RemoveUnReadResponse{
			Code:   project_comment_api.RemoveUnReadResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_comment_api.RemoveUnReadResponse{
			Code:   project_comment_api.RemoveUnReadResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := comment_dao.UnReadDao.Exist(ctx, req.ProjectId, sessionItem.UserId, uint32(req.TargetType), req.TargetId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_comment_api.RemoveUnReadResponse{
			Code: project_comment_api.RemoveUnReadResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = comment_dao.UnReadDao.Remove(sessCtx, req.ProjectId, sessionItem.UserId, uint32(req.TargetType), req.TargetId)
		if err != nil {
			return nil, err
		}
		return &project_comment_api.RemoveUnReadResponse{
			Code: project_comment_api.RemoveUnReadResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	go api_common.SendNoticeToUser(context.Background(), sessionItem.UserId, &notices_comment.RemoveUnReadNotice{
		ProjectId: req.ProjectId,
	})
	return ret.(*project_comment_api.RemoveUnReadResponse), nil
}
